"""
Case Type   : DSS元数据修复工具
Case Name   : dsstbox ssrepair参数修改元数据类型为fs_block
Create At   : 2025/04
Owner       : haomeng
Description :
    1、查看当前卷名
    2、开启dss的debug日志
    3、创建dss文件，并truncate一个大小
    4、查看dss日志文件，筛选出创建文件的metaid
    5、使用dsscmd showdisk查看metaid相关元数据值
    6、通过metaid元数据值筛选出entry.auid为fs_block的metaid
    7、使用dsscmd showdisk查看fs_block相关元数据值
    8、修改部分不支持修改元数据
    9、修改部分支持修改元数据
    10、清理环境，恢复集群状态
Expect      :
    1、获取卷名成功
    2、开启debug日志成功
    3、创建文件成功
    4、获取metaid成功
    5、查看元数据成功
    6、获取fs_block的metaid成功
    7、查看fs_block的元数据成功
    8、修改失败
    9、修改成功
    10、清理环境成功，恢复集群状态成功
History     :
"""

import os
import ast
import time
import unittest

from testcase.utils.Common import Common
from testcase.utils.CommonSH import CommonSH
from testcase.utils.Constant import Constant
from testcase.utils.Logger import Logger
from yat.test import Node
from yat.test import macro


class DSSrepairtools(unittest.TestCase):

    def setUp(self):
        self.log = Logger()
        self.log.info(f'----{os.path.basename(__file__)} start----')
        self.user_node = Node('PrimaryDbUser')
        self.pri_sh = CommonSH('PrimaryDbUser')
        self.constant = Constant()

        self.vol_path = os.path.join(macro.DSS_INSTANCE_PATH, 'cfg/dss_vg_conf.ini')
        self.dss_log_path = os.path.join(macro.DSS_INSTANCE_PATH, 'log/debug/dssinstance.dlog')
        self.file_name = 'dsstbox_ssrepair_file_08.txt'
        self.metadata = ['head.common.checksum', 'head.reserve','head.common.type',
                         'head.common.version', 'head.common.id', 'head.common.flags', 'head.next',
                         'head.ftid', 'head.used_num', 'head.total_num', 'head.index', 'bitmap[0]']
        self.metadata_value = [1185018548, 65535, 1, 553, 4380454325078016, 2, 18446744073709551615,
                               18446744073709551615, 1, 2041, 65533, 1970324836993024]
        self.ft_block = []
        self.fs_block = []

    def test_dsstbox(self):
        text = '-----step1:查看当前卷名;  expect:查看成功-----'
        self.log.info(text)

        res = self.user_node.sh(f"cat {self.vol_path} | awk 'NR==1'").result()
        self.log.info(res)
        self.vol_name = res.split(':')[0]
        vol_value = res.split(':')[1]
        self.log.info(f'vol_name的值是：{self.vol_name}, vol_value的值是：{vol_value}')
        self.assertNotEqual('', self.vol_name, '查看当前卷名失败')

        text = '-----step2:开启debug日志;  expect:开启成功-----'
        self.log.info(text)

        set_debug = f"source {macro.DB_ENV_PATH};" \
                    f"dsscmd setcfg -n _log_LEVEL -v 255 -s both"
        self.log.info(set_debug)
        execute_cmd = self.user_node.sh(set_debug).result()
        self.log.info(execute_cmd)
        self.assertIn('Succeed to set cfg', execute_cmd, '开启debug日志失败')

        text = '-----step3:创建dss文件，并truncate一个大小;  expect:创建成功-----'
        self.log.info(text)

        touch = f"source {macro.DB_ENV_PATH};" \
                f"dsscmd touch -p +{self.vol_name}/{self.file_name}"
        self.log.info(touch)
        execute_touch = self.user_node.sh(touch).result()
        self.log.info(execute_touch)
        self.assertIn('Succeed to create file', execute_touch, '创建文件失败')

        truncate = f"source {macro.DB_ENV_PATH};" \
                   f"dsscmd truncate -p +{self.vol_name}/{self.file_name} -l 8192"
        self.log.info(truncate)
        execute_truncate = self.user_node.sh(truncate).result()
        self.log.info(execute_truncate)
        self.assertIn('Success to truncate file', execute_truncate, 'truncate文件失败')

        text = '-----step4:查看dss日志文件，筛选出创建文件的metaid;  expect:查看成功-----'
        self.log.info(text)

        grep_cmd = f"cat {self.dss_log_path} | grep {self.file_name} | grep metaid | tail -n 1"
        self.log.info(grep_cmd)
        grep_res = self.user_node.sh(grep_cmd).result()
        self.log.info(grep_res)

        ft_metaid = grep_res.split('metaid')[1].split(':')[1].split(' ')[0].strip()
        self.log.info(f'ft_metaid的值是：{ft_metaid}')
        self.assertNotEqual('', ft_metaid, '查看metaid失败')

        text = '-----step5:使用dsscmd showdisk查看metaid相关元数据值;  expect:查看成功-----'
        self.log.info(text)
        expect = 'Succeed to print block'

        show_ft = f"source {macro.DB_ENV_PATH};dsscmd showdisk -g {self.vol_name} -b {ft_metaid} -n 0"
        self.log.info(show_ft)
        get_ft_succeed = self.user_node.sh(show_ft).result()
        get_ft = self.user_node.sh(show_ft).result().split(expect)[0].strip()
        self.log.info(get_ft)
        self.ft_block.append(get_ft_succeed.splitlines())
        self.log.info(self.ft_block)
        self.assertIn('Succeed to print block', get_ft_succeed, '查看元数据结果失败')

        text = '-----step6:通过metaid元数据值筛选出entry.auid为fs_block的metaid;  expect:查看成功-----'
        self.log.info(text)

        res = ''
        for line in get_ft.splitlines():
            if '=' in line:
                res += f"'{line.split('=')[0].strip()}'" + ": "
                if '{' in line:
                    res += "{"
                else:
                    res += f"'{line.split('=')[1].strip()}',"
            else:
                res += f'{line.strip()},'
        tmp = f'{{{res.strip(",").replace(",}", "}")}}}'
        res1 = ast.literal_eval(tmp)
        fs_auid = res1['ft_block']['ft_node']['entry']['auid']
        self.log.info(f'fs_auid的值是：{fs_auid}')
        self.assertNotEqual('', fs_auid, '查看fs_block的metaid失败')

        text = '-----step7:使用dsscmd showdisk查看fs_block相关元数据值;  expect:查看成功-----'
        self.log.info(text)

        show_fs = f"source {macro.DB_ENV_PATH};dsscmd showdisk -g {self.vol_name} -b {fs_auid} -n 0"
        self.log.info(show_fs)
        get_fs = self.user_node.sh(show_fs).result()
        self.log.info(get_fs)
        self.fs_block.append(get_fs.splitlines())
        self.log.info(self.fs_block)

        sum_fs_block = sum(len(item) for sublist in self.fs_block for item in sublist)
        self.log.info(f'sum_fs_block的值是：{sum_fs_block}')
        self.assertIn('Succeed to print block', get_fs, '查看fs_block的元数据结果失败')

        text = '-----step8:修改部分不支持修改元数据;  expect:修改失败-----'
        self.log.info(text)

        for param in self.metadata[:2]:
            cmd1 = f"dsstbox ssrepair -v {vol_value} -t fs_block -i {fs_auid} -s 8192 -k '{param}={self.metadata_value[self.metadata.index(param)]}'"
            self.log.info(cmd1)
            execute_cmd1 = f'''source {macro.DB_ENV_PATH};yes|{cmd1}'''
            self.log.info(execute_cmd1)
            res1 = self.user_node.sh(execute_cmd1).result()
            self.log.info(res1)
            self.assertIn('Failed to execute repair meta info', res1, '修改元数据成功')

        text = '-----step9:修改部分支持修改元数据;  expect:修改成功-----'
        self.log.info(text)

        for param in self.metadata[2:]:
            cmd2 = f"dsstbox ssrepair -v {vol_value} -t fs_block -i {fs_auid} -s 8192 -k '{param}={self.metadata_value[self.metadata.index(param)]}'"
            self.log.info(cmd2)
            execute_cmd2 = f'source {macro.DB_ENV_PATH};yes|{cmd2}'
            self.log.info(execute_cmd2)
            res2 = self.user_node.sh(execute_cmd2).result()
            self.log.info(res2)
            self.assertIn('Succeed to execute repair meta info', res2, '修改元数据失败')

    def tearDown(self):
        text = '-----step10:清理环境，恢复集群状态;  expect:清理成功-----'
        self.log.info(text)

        self.log.info('-----删除dss文件-----')
        del_cmd = f"source {macro.DB_ENV_PATH};dsscmd rm -p +{self.vol_name}/{self.file_name}"
        self.log.info(del_cmd)
        execute_del = self.user_node.sh(del_cmd).result()
        self.log.info(execute_del)
        self.assertIn(f'Succeed to remove device +{self.vol_name}/{self.file_name}', execute_del, '删除文件失败')
        self.log.info(f'----{os.path.basename(__file__)} end----')
